#include "channel.h"
#include <errno.h>
namespace srpc
{
    void TcpRpcChannel::CallMethod(const google::protobuf::MethodDescriptor *method,
                                   google::protobuf::RpcController *controller, const google::protobuf::Message *request,
                                   google::protobuf::Message *response, google::protobuf::Closure *done)
    {
        this->mpResponse = response;
        RpcMessagePB message;
        message.set_type(RPC_TYPE_REQUEST);
        message.set_service(method->service()->name());
        message.set_method(method->name());
        message.set_request(request->SerializeAsString());
        this->mpDone = done;
        std::string message_str = message.SerializeAsString();
        int status = bufferevent_write(mpBufferEvent, message_str.c_str(), message_str.size()); 
        // TODO: what if the request size is big
        std::cout << "send message size: " << message_str.size() << "\t success : " << int(status == 0) << std::endl;
        evbuffer_drain(mpBufferEvent->output, evbuffer_get_length(mpBufferEvent->output));
    }

    void TcpRpcChannel::read_cb(bufferevent *bev, void *arg)
    {
        TcpRpcChannel *thisChannel = (TcpRpcChannel*)arg;
        const int LENGTH = 1024;
        struct evbuffer *input = bufferevent_get_input(bev);
        size_t size = evbuffer_get_length(input);
        char line[LENGTH];
        memset(line, 0, sizeof(line));
        bufferevent_read(bev, line, size);
        evbuffer_drain(input,evbuffer_get_length(input));
        line[size + 1] = '\0';
        printf("Recive message from server, size=%d\n", strlen(line));
        thisChannel->mpRpcMessagePB->ParseFromString(line);
        std::cout << thisChannel->mpRpcMessagePB->DebugString() << std::endl;
        thisChannel->mpResponse->ParseFromString(thisChannel->mpRpcMessagePB->response());
        thisChannel->mpDone->Run();
    }

    void TcpRpcChannel::error_cb(struct bufferevent *bev, short event, void *arg)
    {
        std::cout << "error callback " << std::endl;
    }

    void TcpRpcChannel::SetBufferEvent(int socket, EV_BASE evBase)
    {
        evutil_make_socket_nonblocking(socket);
        mpBufferEvent = bufferevent_socket_new(evBase, socket, BEV_OPT_CLOSE_ON_FREE);
        if (mpBufferEvent == nullptr)
        {
            std::cout << "init mpBufferEvent event failed" << std::endl;
            return;
        }
        bufferevent_setcb(mpBufferEvent, &TcpRpcChannel::read_cb, NULL, &TcpRpcChannel::error_cb, (void *)this);
        bufferevent_enable(mpBufferEvent, EV_READ | EV_WRITE | EV_PERSIST);
    }
}